import java.awt.image.BufferedImage;
import java.io.*;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.*;
import java.net.*;
import java.sql.*;

import javax.imageio.ImageIO;

import static java.lang.System.out;

public class ClientThread extends Thread {

    BufferedReader input;
	OutputStream output;
	PrintWriter printWriter;
    Socket myClientSocket;
    boolean ifStop = false;
    boolean sendImageMode = false;

    // Image
    File myImage;
    FileInputStream myImageStream;
    PreparedStatement myPrepareStatement = null;
    BufferedImage[] bufferImg;


    // Image info
    String myIp = "";
    String image_city = "";
    String image_name ="";
    String image_type = "";
    String image_address = "";
    java.sql.Timestamp image_dt;
    String image_dtStr = "";
    int image_size;
    int image_hotness;

    String head;

    public ClientThread(Socket  client) {
    	head = "HTTP/1.0 200 OK\015\012" +
				"Server: HTTPServer\015\012" +
				"Content-type: image/jpeg\015\012\015\012" +
				"";
    	myClientSocket = client;
      // get input and output streams
    	try{
    		input = new BufferedReader( new InputStreamReader( client.getInputStream())) ;
    		//output = new PrintWriter ( client.getOutputStream(),true);

    		printWriter = new PrintWriter(myClientSocket.getOutputStream());
    		 output = myClientSocket.getOutputStream();


    		// read name
    	}catch( IOException e ){
    	}
    	start();
    }
  /*
    public void run()  {
    	String line;
    	try{
    		while(!ifStop)   {
    			line = input.readLine();
    			//Process the request from client
    			//processRequest(line);
    		} // end of while
    	} // try
    	catch(Exception ex) {
    		System.out.println(ex.getMessage());
    	}
    } // end of run()
    */

    public void run(){
		StringBuffer request=new StringBuffer(80);
	    if(sendImageMode==true){
	    	receiveImage();
	    }
	    else{
			try{
				while(true){

					int c = input.read();
					if (c=='\t'||c=='\n'||c==-1 ) {
	                    			break;
	                }
					request.append((char)c);
				}
				// handle command
				String get=request.toString();
	            		System.out.println(get);
	            		StringTokenizer st=new StringTokenizer(get);
	            		String method=st.nextToken();
	            		InputStream fis = null;
				if(method.equals("GET")){
					String fileName=st.nextToken();
					String strId = fileName.substring(1);
					int id = Integer.parseInt(strId);

					System.out.println("image id"+id);

					fis = retrieveImage(id);

					output.write(head.getBytes());
					byte[] buffer = new byte[1024];
					int bytes = 0;
					while((bytes = fis.read(buffer))!=-1){
						output.write(buffer,0,bytes);
					}
					System.out.println("SendImage "+id);
					output.flush();

					//while(inStream.available()!=0){
					//	out.write((char)inStream.readByte());
					//}
					output.close();
				}
				else if(method.equals("INFO")){
					String infoContent=st.nextToken();
					if(infoContent.equals("IMAGE")){
						infoContent=st.nextToken();
						int imageId = Integer.parseInt(infoContent);

						Statement myStatement = PichubServer.sqlCon.createStatement();
						ResultSet rs = null;
		        		rs = myStatement.executeQuery("SELECT name,type,adress,city,dt,hotness From image WHERE id = '" + imageId +"'");
		        		if(rs.next()){
		        			image_name = rs.getString(1);
		        			image_type = rs.getString(2);
		        			image_address = rs.getString(3);
		        			image_city = rs.getString(4);
		        			image_dt = rs.getTimestamp(5);
		        			image_dtStr = image_dt.toString();
		        			//image_size = rs.getInt(6);
		        			image_hotness = rs.getInt(6);
		        		}
		        		String returnInfo = "IMAGEINFO "+image_name+"#"+image_type+"#"+image_address+"#"+image_city+"#"+image_dtStr+"#"+image_hotness;
		        		output.write(returnInfo.getBytes());
		        		output.flush();
		        		output.close();
					}
					else if(infoContent.equals("COMMENT")){
						infoContent=st.nextToken();
						int imageId = Integer.parseInt(infoContent);
						int comment_id = 0;
						String comment_content="";
						java.sql.Timestamp comment_dt;
						String comment_dtStr = "";

						Statement myStatement = PichubServer.sqlCon.createStatement();
						ResultSet rs = null;
		        		rs = myStatement.executeQuery("SELECT id,content,dt From comments WHERE imageId = '" + imageId +"'");
						String[] comments = new String[200];
						int row=0;
		        		while(rs.next()){
		        			comment_id = rs.getInt(1);
		        			comment_content = rs.getString(2);
		        			comment_dt = rs.getTimestamp(3);
		        			comment_dtStr = comment_dt.toString();
							comment_dtStr = comment_dtStr.replace(' ','_');
		        			comments[row] = comment_id+"#"+comment_content+"#"+comment_dtStr;
							row++;
		        		}
		        		String returnInfo = "COMMENTINFO "+ row+" ";
						for(int i = 0 ; i < row ; i++ )
						{
							returnInfo += comments[i]+"&&";
						}
		        		output.write(returnInfo.getBytes());
		        		output.flush();
		        		output.close();
					}
				}
				else if(method.equals("SENDIMAGEON")){
					sendImageMode = true;
				}
				else if(method.equals("GETIMAGEID")){
					String infoContent=st.nextToken();
					// GETIMAGEID NEW 3 POP 5
					if(infoContent.equals("LAST")){
						//String city = st.nextToken();
						//int numOfNew = Integer.parseInt(st.nextToken());

						String query = "SELECT id FROM image ORDER BY id DESC LIMIT 1";
						myPrepareStatement = PichubServer.sqlCon.prepareStatement(query);
						//myPrepareStatement.setString(1, city);
						ResultSet rs = null;
		        		rs = myPrepareStatement.executeQuery();
						int id = 0;
						if(rs.next()){
		        			id = rs.getInt(1);
						}
						String returnStr = id+"";
						System.out.println("RETURN IMAGE ID: "+id);
		        		output.write(returnStr.getBytes());
		        		output.flush();
		        		output.close();
					}
					else if(infoContent.equals("NEW")){
						String city = st.nextToken();
						int numOfNew = Integer.parseInt(st.nextToken());

						String query = "SELECT id FROM image WHERE city=? ORDER BY dt DESC LIMIT ?;";
						myPrepareStatement = PichubServer.sqlCon.prepareStatement(query);
						myPrepareStatement.setString(1, city);
						myPrepareStatement.setInt(2, numOfNew);

						ResultSet rs = null;
		        		rs = myPrepareStatement.executeQuery();
		        		int[] id = new int[numOfNew];
		        		int row=0;
		        		while(rs.next()){
		        			id[row] = rs.getInt(1);
		        			row++;
		        		}
		        		String returnStr = row+" ";
		        		for(int i=0;i<row;i++){
		        			if(i==row-1){
		        				returnStr+=id[i]+"";
		        			}
		        			else{
		        				returnStr+=id[i]+"#";
		        			}
		        		}
						System.out.println("RETURN IMAGE ID: "+returnStr);
		        		output.write(returnStr.getBytes());
		        		output.flush();
		        		output.close();

					}
					else if(infoContent.equals("OLD")){
						String city = st.nextToken();
						String lastDt = st.nextToken();
						int numOfOld = Integer.parseInt(st.nextToken());

						String query = "SELECT id FROM image WHERE city=? AND dt<? ORDER BY dt DESC LIMIT ?;";
						myPrepareStatement = PichubServer.sqlCon.prepareStatement(query);
						myPrepareStatement.setString(1, city);

						myPrepareStatement.setString(2, lastDt);
						myPrepareStatement.setInt(3, numOfOld);

						ResultSet rs = null;
		        		rs = myPrepareStatement.executeQuery();
		        		int[] id = new int[numOfOld];
		        		int row=0;
		        		while(rs.next()){
		        			id[row] = rs.getInt(1);
		        			row++;
		        		}
		        		String returnStr = row+" ";
		        		for(int i=0;i<row;i++){
		        			if(i==row-1){
		        				returnStr+=id[i]+"";
		        			}
		        			else{
		        				returnStr+=id[i]+"#";
		        			}
		        		}
						System.out.println("RETURNID: "+returnStr);
		        		output.write(returnStr.getBytes());
		        		output.flush();
		        		output.close();

					}
					else if(infoContent.equals("POP")){
						String city = st.nextToken();
						System.out.println(st.countTokens()+"");
						String returnStr="";
						if(st.countTokens()==2){
						int lastPop = Integer.parseInt(st.nextToken());
						int numOfPop = Integer.parseInt(st.nextToken());

						String query = "SELECT id FROM image WHERE city=? AND hotness<? ORDER BY hotness DESC LIMIT ?;";
						myPrepareStatement = PichubServer.sqlCon.prepareStatement(query);
						myPrepareStatement.setString(1, city);

						myPrepareStatement.setInt(2, lastPop);
						myPrepareStatement.setInt(3, numOfPop);

						ResultSet rs = null;
		        		rs = myPrepareStatement.executeQuery();
		        		int[] id = new int[numOfPop];
		        		int row=0;
		        		while(rs.next()){
		        			id[row] = rs.getInt(1);
		        			row++;
		        		}
		        		returnStr = row+" ";
		        		for(int i=0;i<row;i++){
		        			if(i==row-1){
		        				returnStr+=id[i]+"";
		        			}
		        			else{
		        				returnStr+=id[i]+"#";
		        			}
		        		}
						}
						else if(st.countTokens()==1){
						int numOfPop = Integer.parseInt(st.nextToken());

						String query = "SELECT id FROM image WHERE city=? ORDER BY hotness DESC LIMIT ?;";
						myPrepareStatement = PichubServer.sqlCon.prepareStatement(query);
						myPrepareStatement.setString(1, city);

						myPrepareStatement.setInt(2, numOfPop);

						ResultSet rs = null;
		        		rs = myPrepareStatement.executeQuery();
		        		int[] id = new int[numOfPop];
		        		int row=0;
		        		while(rs.next()){
		        			id[row] = rs.getInt(1);
		        			row++;
		        		}
		        		returnStr = row+" ";
		        		for(int i=0;i<row;i++){
		        			if(i==row-1){
		        				returnStr+=id[i]+"";
		        			}
		        			else{
		        				returnStr+=id[i]+"#";
		        			}
		        		}
						}
		        		output.write(returnStr.getBytes());
		        		output.flush();
		        		output.close();
					}
				}
				else if(method.equals("SEND")){
					String infoContent=st.nextToken();
					if(infoContent.equals("IMAGEINFO")){
						infoContent=st.nextToken();
						int imageId = Integer.parseInt(infoContent);
						infoContent = st.nextToken();
						System.out.println(infoContent);
						// Now it is the info of the image
						String sp="#";
						String[] infoImage = infoContent.split(sp);

						String query = "UPDATE image SET name = ?, type=?, adress=?, city=? WHERE id=?;";
						myPrepareStatement = PichubServer.sqlCon.prepareStatement(query);
						myPrepareStatement.setString(1, infoImage[0]);
						myPrepareStatement.setString(2, infoImage[1]);
						myPrepareStatement.setString(3, infoImage[2]);
						myPrepareStatement.setString(4, infoImage[3]);
						myPrepareStatement.setInt(5, imageId);
						myPrepareStatement.executeUpdate();
					}
					else if(infoContent.equals("COMMENTINFO")){
						infoContent=st.nextToken();
						int imageId = Integer.parseInt(infoContent);
						infoContent = st.nextToken();
						// Now it is the info of the comment
						String query = "INSERT INTO comments(content,imageId) VALUES(?,?)";
						myPrepareStatement = PichubServer.sqlCon.prepareStatement(query);
						myPrepareStatement.setString(1, infoContent);
						myPrepareStatement.setInt(2, imageId);

						myPrepareStatement.executeUpdate();
					}

				}
				else if(method.equals("LIKE")){
					int id = Integer.parseInt(st.nextToken());
					String query = "UPDATE image SET hotness=hotness+1 WHERE id=?;";
					myPrepareStatement = PichubServer.sqlCon.prepareStatement(query);
					myPrepareStatement.setInt(1, id);
					myPrepareStatement.executeUpdate();
				}



			}
			catch(Exception e){
				e.printStackTrace();
			}
			finally{
				if(myClientSocket!=null){
					try {
						myClientSocket.close();
					} catch (Exception e) {
						e.printStackTrace();
					}

				}
			}
	    }
	}


    private void processRequest(String line){
    	try{
    	if ( line.equals("QUIT") ) {
			synchronized(this)
			{
				stopThread();
			}

		}
		// client want to download image
		else if(line.equals("DOWNLOAD IMAGE")){
			//
			line = input.readLine();
			if(line.equals("NEW"))
			{
				// Get information: city$num of popular image$num of old image
				line = input.readLine();
				String[] info = line.split("$");
				String city = info[0];
				int numOfPop = Integer.parseInt(info[1]);
				int numOfOld = Integer.parseInt(info[2]);

				// Retrieve image
				bufferImg = new BufferedImage[numOfPop];
				//retrieveImage(numOfPop, city,true);
				sendImage();
			}
			else if(line.equals("OLD")){
				String[] info = line.split("$");
				int numOfOld = Integer.parseInt(info[0]);
				int numOfPop = Integer.parseInt(info[1]);
				int lastPop = Integer.parseInt(info[2]);;
				String oldTimestamp = info[3];

			}
		}
		// client want to download image info
		else if(line.equals("DOWNLOAD INFO")){
			line = input.readLine();
			int imageId = Integer.parseInt(line);

		}
		// client want to download image comment
		else if(line.equals("DOWNLOAD COMMENT")){
			line = input.readLine();
			String[] info = line.split("|");

		}
		// client want to upload image
		else if(line.equals("UPLOAD IMAGE")){
			line = input.readLine();
			String[] info = line.split("|");
		}
		// client want to upload image info
		else if(line.equals("UPLOAD INFO")){
			line = input.readLine();
			String[] info = line.split("|");
		}
		// client want to upload comment
		else if(line.equals("UPLOAD COMMENT")){
			line = input.readLine();
			String[] info = line.split("|");
		}
    	}catch(Exception e){
    		System.err.println(e);
    	}
    }

    public String getIp(){
    	return myIp;
    }

    public void stopThread(){
    	ifStop = true;
    }



    private void saveImage(){
    	try{
    		myImageStream = new FileInputStream( myImage );
    		myPrepareStatement = PichubServer.sqlCon.prepareStatement("INSERT INTO image(imageData) VALUES (?)");
    		myPrepareStatement.setBinaryStream(1, (InputStream)myImageStream, (int)(myImage.length()));
    		myPrepareStatement.executeUpdate();

    	}catch(Exception e){
    	}
    }
    /*
    public void sendImage(){
    	System.out.println("send image start");
    	byte [] data = new byte[(int)myImage.length()];
    	System.out.println("Send " + (int)myImage.length() + " bytes");
    	try{
    		FileInputStream in = new FileInputStream(myImage);
    		//OutputStream out = myClientSocket.getOutputStream();
    		FileOutputStream outStream = (FileOutputStream)myClientSocket.getOutputStream();
    		int size;
    		int m=0;
             while((size = in.read(data))>0){
            	 outStream.write(data,0,size);
            	 m+=size;
             }

             System.out.println(m);
             outStream.flush();

            // out.close();
             in.close();
    	}catch(Exception e){
    		System.err.println(e);
    	}
    	System.out.println("send image finished");
    }
    */
    public void sendImage(){
    	System.out.println("send image start");
    	int i = 0;
    	for(i=0;i<bufferImg.length;i++){
    	try{

    		ByteArrayOutputStream os = new ByteArrayOutputStream();
    		ImageIO.write(bufferImg[i],"jpg",os);
    		InputStream in = new ByteArrayInputStream(os.toByteArray());
    		FileOutputStream outStream = (FileOutputStream)myClientSocket.getOutputStream();
    		int size;
    		int m=0;
    		byte [] data = new byte[os.size()];
             while((size = in.read(data))>0){
            	 outStream.write(data,0,size);
            	 m+=size;
             }

             System.out.println(m);
             outStream.flush();

            // out.close();
             in.close();
    	}catch(Exception e){
    		System.err.println(e);
    	}
    	}
    	System.out.println("send image finished");
    }



    private void receiveImage(){
    	BufferedImage buffer = null;
    	System.out.println("Receive started");
    	try{
    		InputStream img = myClientSocket.getInputStream();
    		if(img!=null)System.out.println("Data received" );
    		else System.out.println("Data receive fails");
    	 	myImage = new File("tmp.jpg");
    	 	OutputStream out = new FileOutputStream(myImage);

    	 	buffer = ImageIO.read(img);

		 	if(buffer==null) System.err.println("Image convert fails");
		 	System.out.println("Image converted");
		 	ImageIO.write(buffer, "jpg", myImage);

		 	System.out.println("Image saved");
    	}catch(Exception e){
    		System.err.println("Receive");
    		System.err.println(e);
    	}
    	System.out.println("Receive finished");
    }

    private void saveOtherInfo(){
    	try{

    		myPrepareStatement = PichubServer.sqlCon.prepareStatement("INSERT INTO image(name,type,address,city,dt,size,hotness) VALUES (?,?,?,?,?,?,?)");
    		myPrepareStatement.setString(1,image_name);
    		myPrepareStatement.setString(2,image_type);
    		myPrepareStatement.setString(3,image_address);
    		myPrepareStatement.setString(4,image_city);
    		java.util.Date image_date = new java.util.Date();
    		image_dt = new java.sql.Timestamp(image_date.getTime());
    		myPrepareStatement.setTimestamp(5, image_dt);
    		myPrepareStatement.setInt(6, image_size);
    		myPrepareStatement.setInt(7, 0);

    		myPrepareStatement.executeUpdate();
    	}catch(Exception e){
    		System.err.println(e);
    	}
    }

    private void retrieveOtherInfo(int id){

    	ResultSet rs = null;
    	BufferedImage buffer = null;
    	try{
    		Statement myStatement = PichubServer.sqlCon.createStatement();
    		rs = myStatement.executeQuery("SELECT name, type, address, city, dt, size, hotness From image WHERE id = '" + id +"'");
    		if(rs.next()){
    			image_name = rs.getString(1);
    			image_type = rs.getString(2);
    			image_address = rs.getString(3);
    			image_city = rs.getString(4);
    			image_dt = rs.getTimestamp(5);
    			image_size = rs.getInt(6);
    			image_hotness = rs.getInt(7);
    		}
    	}catch(Exception e){
    		System.err.println(e);
    	}

    }

    private int[] retrieveImageId(int num , String city , Boolean ifNew , String timeStamp){
    	int[] idBack = new int[num];
    	// If requesting new image
    	if(ifNew == true)
    	{
    		System.out.println("retrieve image new id start");
        	ResultSet rs = null;
        	try{
        		Statement myStatement = PichubServer.sqlCon.createStatement();
        		rs = myStatement.executeQuery("SELECT id From image WHERE city = '" + city +"' ORDER BY ds LIMIT "+num+";");
        		int row = 0;
        		while(rs.next()){
        			idBack[row] = rs.getInt(1);
        			row++;
        		}
        	}catch(Exception e){
        		System.err.println("RETRIEVE NEW ID ERROR: "+e);
        	}
    	}
    	else{
    		System.out.println("retrieve image old id start");
        	ResultSet rs = null;
        	try{
        		Statement myStatement = PichubServer.sqlCon.createStatement();
        		rs = myStatement.executeQuery("SELECT id From image WHERE city = '" + city +"' ORDER BY ds LIMIT "+num);
        		int row = 0;
        		while(rs.next()){
        			idBack[row] = rs.getInt(1);
        			row++;
        		}
        	}catch(Exception e){
        		System.err.println("RETRIEVE NEW ID ERROR: "+e);
        	}
    	}

        	System.out.println("retrieve image id finished");
        	return idBack;
        }


    private InputStream retrieveImage(int id){
    	System.out.println("retrieve image start");
    	InputStream streamBack = null;
        	ResultSet rs = null;
        	try{
        		Statement myStatement = PichubServer.sqlCon.createStatement();
        		rs = myStatement.executeQuery("SELECT imageData From image WHERE id = '" + id +"'");
        		if(rs.next()){
        			streamBack = rs.getBinaryStream(1);
        			 myImage = new File("tmp.jpg");
        			// System.err.println("Here");
        		}
        	}catch(Exception e){
        		System.err.println("RETRIEVE IMAGE ERROR: " +e);
        	}

        	System.out.println("retrieve image finished");
        	return streamBack;
        }


}
